package com.jzr.netty.service;

import com.jzr.common.util.LogUtil;
import com.jzr.common.util.U;
import com.jzr.netty.base.DeviceMap;
import com.jzr.netty.base.TDeviceVo;
import com.jzr.netty.common.base.BaseMsg;
import com.jzr.netty.common.base.DeviceLive;
import com.jzr.netty.common.protocol.*;
import com.jzr.netty.db1.service.TDeviceService;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

@Component
@ChannelHandler.Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler<BaseMsg> {
    @Autowired
    private TDeviceService deviceService;

    private ChannelHandlerContext ctx;

    private Logger log = LoggerFactory.getLogger(this.getClass());

    private static NettyServerHandler nettyServerHandler;

    public static NettyServerHandler getNettyServerHandler() {
        if (nettyServerHandler == null) {
            nettyServerHandler = new NettyServerHandler();
            return nettyServerHandler;
        } else {
            return nettyServerHandler;
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        SocketChannel channel = (SocketChannel) ctx.channel();
        //channel失效，从Map中移除
        int i = DeviceMap.remove(channel);
        //log.info("移除:" + channel.remoteAddress().getAddress());
    }

    private void registerDevice(ChannelHandlerContext ctx, BaseMsg baseMsg){
        SocketChannel channel = (SocketChannel) ctx.channel();

        switch (baseMsg.getType()){
            case REGISTER:{
                RegisterRequest request = (RegisterRequest) baseMsg;
                TDeviceVo deviceVo = new TDeviceVo();
                BeanUtils.copyProperties(request,deviceVo);
                deviceVo.setLastUpTime(LocalDateTime.now());
                deviceVo.setSocketChannel(channel);
                DeviceMap.add(request.getDeviceIp(), deviceVo);
                deviceService.saveByRegister(deviceVo);
                //DeviceUtils.saveByRegister(deviceVo);
            }
            break;
            case PING:{
                PingMsg request = (PingMsg) baseMsg;
                TDeviceVo deviceVo = new TDeviceVo();
                BeanUtils.copyProperties(request,deviceVo);
                deviceVo.setLastUpTime(LocalDateTime.now());
                deviceVo.setSocketChannel(channel);
                DeviceMap.add(request.getDeviceIp(), deviceVo);
                deviceService.saveByRegister(deviceVo);
                //DeviceUtils.saveByRegister(deviceVo);
            }
            break;
            default:{

            }
        }

    }

    protected void channelRead0(ChannelHandlerContext ctx, BaseMsg baseMsg) throws Exception {
        log.info("baseMsg.getType():" + baseMsg.getType().toString());
        this.ctx = ctx;
        switch (baseMsg.getType()) {
            case REGISTER: {// 注册
                RegisterResponse response = new RegisterResponse();
                try {
                    RegisterRequest request = (RegisterRequest) baseMsg;
                    registerDevice(ctx, baseMsg);
                    BeanUtils.copyProperties(request, response);
                    ctx.writeAndFlush(response);
                    log.info("REGISTER send response");
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;
            case PING: {
                PingResponse response = new PingResponse();
                try {
                    PingMsg request = (PingMsg) baseMsg;
                    registerDevice(ctx, baseMsg);
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;
            //语音协议
            case VOICE: {
                VoiceResponse response = new VoiceResponse();
                try {
                    LogUtil.ROOT_LOG.error("语音协议");
                    VoiceRequest request = (VoiceRequest) baseMsg;
                    SocketChannel channel = DeviceMap.get(request.getNurseboardIp());
                    if (channel != null) {
                        channel.writeAndFlush(request);
                        LogUtil.ROOT_LOG.error("语音协议" + "床头卡 IP :  " + request.getDeviceIp() + "护理板IP : " + request.getNurseboardIp());
                    }
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }

            }
            break;
            //取消语音协议
            case CANCEL_VOICE: {
                CancelVoiceResponse response = new CancelVoiceResponse();
                try {
                    LogUtil.ROOT_LOG.error("取消语音协议");
                    CancelVoiceRequest request = (CancelVoiceRequest) baseMsg;
                    SocketChannel channel = DeviceMap.get(request.getCancelIp());
                    if (channel != null) {
                        channel.writeAndFlush(request);
                        LogUtil.ROOT_LOG.error("取消语音协议" + "发送方 IP :  " + request.getDeviceIp() + "接受方 IP : " + request.getCancelIp());
                    }
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;
            //视频
            case VIDEO: {
                VideoResponse response = new VideoResponse();
                try {
                    VideoRequest request = (VideoRequest) baseMsg;

                    SocketChannel channel = DeviceMap.get(request.getDeviceIp());
                    if (channel != null) {
                        channel.writeAndFlush(request);
                    }
                    //回复请求者
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;

            //取消视频
            case CANCEL_VIDEO: {
                CancelVideoResponse response = new CancelVideoResponse();
                try {
                    CancelVideoRequest request = (CancelVideoRequest) baseMsg;
                    SocketChannel channel = DeviceMap.get(request.getDeviceIp());
                    if (channel != null) {
                        channel.writeAndFlush(request);
                    }
                    //回复请求者
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;

            //获取在线设备列表
            case GET_DEVICE_LIST:{
                GetDeviceListResponse response = new GetDeviceListResponse();
                try {
                    GetDeviceListRequest request = (GetDeviceListRequest) baseMsg;
                    List<DeviceLive> list = null;
                    if(request.getDeviceNoList() != null && !request.getDeviceNoList().isEmpty()) {
                        list = DeviceMap.getDeviceLive(request.getDeviceNoList());
                    }else{
                        list = DeviceMap.getDeviceLive(request.getDeptCode(), request.getDeviceType());
                    }
                    log.info(list==null?"0设备":list.size()+"设备");
                    response.setList(list);
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;

            //app应用程序升级协议
            case UPGRADE: {
                UpgradeResponse response = new UpgradeResponse();
                try {
                    UpgradeDeptRequest request = (UpgradeDeptRequest) baseMsg;
                    String deviceIp = request.getDeviceIp();

                    UpgradeRequest newRequest = new UpgradeRequest();
                    BeanUtils.copyProperties(request,newRequest);
                    newRequest.setDeviceIp(null);

                    int count = 0;
                    if(U.isNotBlank(deviceIp)){
                        String[] ipList = deviceIp.split(",");
                        for(String ip : ipList){
                            SocketChannel channel = DeviceMap.get(ip);
                            if(channel != null){
                                channel.writeAndFlush(newRequest);
                                count++;
                            }
                        }
                    }else if(U.isNotBlank(request.getDeviceType())){
                        List<SocketChannel> list = DeviceMap.getSocketChannelList(request.getDeptCode(), request.getDeviceType());
                        for(SocketChannel channel : list){
                            channel.writeAndFlush(newRequest);
                            count++;
                        }
                    }
                    response.setStatus(0);
                    response.setDeviceCount(count);
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;

            //重新加载数据
            case RELOAD_DATA:{
                ReloadDataResponse response = new ReloadDataResponse();
                try {
                    ReloadDataDeptRequest request = (ReloadDataDeptRequest) baseMsg;
                    String deviceIp = request.getDeviceIp();

                    ReloadDataRequest newRequest = new ReloadDataRequest();
                    BeanUtils.copyProperties(request,newRequest);
                    newRequest.setDeviceIp(null);

                    int count = 0;
                    if(U.isNotBlank(deviceIp)){
                        String[] ipList = deviceIp.split(",");
                        for(String ip : ipList){
                            SocketChannel channel = DeviceMap.get(ip);
                            if(channel != null){
                                channel.writeAndFlush(newRequest);
                                count++;
                            }
                        }
                    }else if(U.isNotBlank(request.getDeviceType())){
                        List<SocketChannel> list = DeviceMap.getSocketChannelList(request.getDeptCode(),request.getDeviceType());
                        for(SocketChannel channel : list){
                            channel.writeAndFlush(newRequest);
                            count++;
                        }
                    }
                    response.setStatus(0);
                    response.setDeviceCount(count);
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;

            case RESTART_APP:{
                RestartAppResponse response = new RestartAppResponse();
                try {
                    RestartAppDeptRequest request = (RestartAppDeptRequest) baseMsg;
                    String deviceIp = request.getDeviceIp();

                    ReloadDataRequest newRequest = new ReloadDataRequest();
                    BeanUtils.copyProperties(request,newRequest);
                    newRequest.setDeviceIp(null);

                    int count = 0;
                    if(U.isNotBlank(deviceIp)){
                        String[] ipList = deviceIp.split(",");
                        for(String ip : ipList){
                            SocketChannel channel = DeviceMap.get(ip);
                            if(channel != null){
                                channel.writeAndFlush(newRequest);
                                count++;
                            }
                        }
                    }else if(U.isNotBlank(request.getDeviceType())){
                        List<SocketChannel> list = DeviceMap.getSocketChannelList(request.getDeptCode(),request.getDeviceType());
                        for(SocketChannel channel : list){
                            channel.writeAndFlush(newRequest);
                            count++;
                        }
                    }
                    response.setStatus(0);
                    response.setDeviceCount(count);
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;

            case RESTART_DEVICE:{
                RestartDeviceResponse response = new RestartDeviceResponse();
                try {
                    RestartDeviceDeptRequest request = (RestartDeviceDeptRequest) baseMsg;
                    String deviceIp = request.getDeviceIp();

                    RestartDeviceRequest newRequest = new RestartDeviceRequest();
                    BeanUtils.copyProperties(request,newRequest);
                    newRequest.setDeviceIp(null);

                    int count = 0;
                    if(U.isNotBlank(deviceIp)){
                        String[] ipList = deviceIp.split(",");
                        for(String ip : ipList){
                            SocketChannel channel = DeviceMap.get(ip);
                            if(channel != null){
                                channel.writeAndFlush(newRequest);
                                count++;
                            }
                        }
                    }else if(U.isNotBlank(request.getDeviceType())){
                        List<SocketChannel> list = DeviceMap.getSocketChannelList(request.getDeptCode(), request.getDeviceType());
                        for(SocketChannel channel : list){
                            channel.writeAndFlush(newRequest);
                            count++;
                        }
                    }
                    response.setStatus(0);
                    response.setDeviceCount(count);
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;


            case LOCK_SCREEN:{
                LockScreenResponse response = new LockScreenResponse();
                try {
                    LockScreenDeptRequest request = (LockScreenDeptRequest) baseMsg;
                    String deviceIp = request.getDeviceIp();

                    LockScreenRequest newRequest = new LockScreenRequest();
                    BeanUtils.copyProperties(request,newRequest);
                    newRequest.setDeviceIp(null);

                    int count = 0;
                    if(U.isNotBlank(deviceIp)){
                        String[] ipList = deviceIp.split(",");
                        for(String ip : ipList){
                            SocketChannel channel = DeviceMap.get(ip);
                            if(channel != null){
                                channel.writeAndFlush(newRequest);
                                count++;
                            }
                        }
                    }else if(U.isNotBlank(request.getDeviceType())){
                        List<SocketChannel> list = DeviceMap.getSocketChannelList(request.getDeptCode(), request.getDeviceType());
                        for(SocketChannel channel : list){
                            channel.writeAndFlush(newRequest);
                            count++;
                        }
                    }
                    response.setStatus(0);
                    response.setDeviceCount(count);
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;

            case CAPTURE_SCREEN:{
                CaptureScreenResponse response = new CaptureScreenResponse();
                try {
                    CaptureScreenRequest request = (CaptureScreenRequest) baseMsg;
                    if(U.isNotBlank(request.getDeviceIp())) {
                        SocketChannel channel = DeviceMap.get(request.getDeviceIp());
                        if (channel != null) {
                            channel.writeAndFlush(request);
                            response.setStatus(0);
                        } else {
                            response.setStatus(-1);
                        }
                    }else{
                        response.setStatus(-2);
                    }
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    response.setStatus(-1);
                    response.setMessage(ex.getMessage());
                    ctx.writeAndFlush(response);
                }
            }
            break;
            case VITAL_SIGN:{
                VitalSignResponse response = new VitalSignResponse();
                try {
                    VitalSignRequest request = (VitalSignRequest) baseMsg;
                    if(U.isNotBlank(request.getDeviceIp())) {
                        SocketChannel channel = DeviceMap.get(request.getDeviceIp());
                        if (channel != null) {
                            channel.writeAndFlush(request);

                        } else {

                        }
                    }else{

                    }
                    ctx.writeAndFlush(response);
                }catch (Exception ex){
                    ex.printStackTrace();
                    ctx.writeAndFlush(response);
                }
            }
            break;
            default:
                log.info("default");
                break;
        }
        ReferenceCountUtil.release(baseMsg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        closeOnFlush(ctx.channel());  // 发生异常，关闭链路
    }

    static void closeOnFlush(Channel ch) {
        if (ch.isActive()) {
            ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
    }
}